package com.lifeonwalden.game.mindustry.processor;

import com.lifeonwalden.game.mindustry.Global;
import com.lifeonwalden.game.mindustry.constant.Toward;
import com.lifeonwalden.game.mindustry.model.Footprint;
import com.lifeonwalden.game.mindustry.world.Coordinate;
import com.lifeonwalden.game.mindustry.world.Point;

import java.util.Optional;
import java.util.function.BiFunction;

public class PathFinder implements Runnable {
    public Footprint[][] footprints;
    public Coordinate startPoint;
    public Coordinate targetPoint;
    private static BiFunction<PathFinder, Coordinate, Optional<Boolean>>[] Move = new BiFunction[4];

    static {
        Move[Toward.UP.ordinal()] = (pathFinder, currentPoint) -> {
            Footprint currentFootprint = pathFinder.footprints[currentPoint.x][currentPoint.y];
            if (null == currentFootprint) {
                currentFootprint = new Footprint();
                pathFinder.footprints[currentPoint.x][currentPoint.y] = currentFootprint;
            }

            if (!currentFootprint.up) {
                return Optional.of(Boolean.FALSE);
            }

            Point nextPoint = Global.world.points[currentPoint.x][currentPoint.y + 1];
            if (null != nextPoint && null == nextPoint.obstruction) {
                if (Toward.UP == currentFootprint.toward) {
                    return Optional.empty();
                } else {
                    currentFootprint.toward = Toward.UP;
                    currentPoint.y += 1;
                    return Optional.of(Boolean.TRUE);
                }
            } else {
                currentFootprint.up = false;
                pathFinder.footprints[currentPoint.x][currentPoint.y + 1] = null;
                return Optional.of(Boolean.FALSE);
            }
        };

        Move[Toward.RIGHT.ordinal()] = (pathFinder, currentPoint) -> {
            Footprint currentFootprint = pathFinder.footprints[currentPoint.x][currentPoint.y];
            if (null == currentFootprint) {
                currentFootprint = new Footprint();
                pathFinder.footprints[currentPoint.x][currentPoint.y] = currentFootprint;
            }

            if (!currentFootprint.right) {
                return Optional.of(Boolean.FALSE);
            }

            Point nextPoint = Global.world.points[currentPoint.x + 1][currentPoint.y];
            if (null != nextPoint && null == nextPoint.obstruction) {
                if (Toward.RIGHT == currentFootprint.toward) {
                    return Optional.empty();
                } else {
                    currentFootprint.toward = Toward.RIGHT;
                    currentPoint.x += 1;
                    return Optional.of(Boolean.TRUE);
                }
            } else {
                currentFootprint.right = false;
                pathFinder.footprints[currentPoint.x + 1][currentPoint.y] = null;
                return Optional.of(Boolean.FALSE);
            }
        };

        Move[Toward.BOTTOM.ordinal()] = (pathFinder, currentPoint) -> {
            Footprint currentFootprint = pathFinder.footprints[currentPoint.x][currentPoint.y];
            if (null == currentFootprint) {
                currentFootprint = new Footprint();
                pathFinder.footprints[currentPoint.x][currentPoint.y] = currentFootprint;
            }

            if (!currentFootprint.bottom) {
                return Optional.of(Boolean.FALSE);
            }

            Point nextPoint = Global.world.points[currentPoint.x][currentPoint.y - 1];
            if (null != nextPoint && null == nextPoint.obstruction) {
                if (Toward.BOTTOM == currentFootprint.toward) {
                    return Optional.empty();
                } else {
                    currentFootprint.toward = Toward.BOTTOM;
                    currentPoint.y -= 1;
                    return Optional.of(Boolean.TRUE);
                }
            } else {
                currentFootprint.bottom = false;
                pathFinder.footprints[currentPoint.x][currentPoint.y - 1] = null;
                return Optional.of(Boolean.FALSE);
            }
        };

        Move[Toward.LEFT.ordinal()] = (pathFinder, currentPoint) -> {
            Footprint currentFootprint = pathFinder.footprints[currentPoint.x][currentPoint.y];
            if (null == currentFootprint) {
                currentFootprint = new Footprint();
                pathFinder.footprints[currentPoint.x][currentPoint.y] = currentFootprint;
            }

            if (!currentFootprint.left) {
                return Optional.of(Boolean.FALSE);
            }

            Point nextPoint = Global.world.points[currentPoint.x - 1][currentPoint.y];
            if (null != nextPoint && null == nextPoint.obstruction) {
                if (Toward.LEFT == currentFootprint.toward) {
                    return Optional.empty();
                } else {
                    currentFootprint.toward = Toward.LEFT;
                    currentPoint.x -= 1;
                    return Optional.of(Boolean.TRUE);
                }
            } else {
                currentFootprint.left = false;
                pathFinder.footprints[currentPoint.x - 1][currentPoint.y] = null;
                return Optional.of(Boolean.FALSE);
            }
        };
    }

    public PathFinder(short x, short y, Coordinate startPoint, Coordinate targetPoint) {
        this.footprints = new Footprint[x][y];
        this.startPoint = startPoint;
        this.targetPoint = targetPoint;
    }

    @Override
    public void run() {

    }

    private void updatePath() {
        Coordinate currentPoint = new Coordinate(startPoint.x, startPoint.y);
        Toward stepOne, stepTow, stepThree, stepFour;

        while (true) {
            if (Math.abs(currentPoint.x - targetPoint.x) <= 8 && Math.abs(currentPoint.y - targetPoint.y) <= 8) {
                return;
            }

            if (targetPoint.x > currentPoint.x) {
                stepOne = Toward.RIGHT;
                stepThree = Toward.LEFT;
            } else {
                stepOne = Toward.LEFT;
                stepThree = Toward.RIGHT;
            }

            if (targetPoint.y > currentPoint.y) {
                stepTow = Toward.BOTTOM;
                stepFour = Toward.UP;
            } else {
                stepTow = Toward.UP;
                stepFour = Toward.BOTTOM;
            }

            Optional<Boolean> moveAction = Move[stepOne.ordinal()].apply(this, currentPoint);
            if (moveAction.isPresent()) {
                if (moveAction.get()) {
                    continue;
                }
            } else {
                return;
            }

            moveAction = Move[stepTow.ordinal()].apply(this, currentPoint);
            if (moveAction.isPresent()) {
                if (moveAction.get()) {
                    continue;
                }
            } else {
                return;
            }

            moveAction = Move[stepThree.ordinal()].apply(this, currentPoint);
            if (moveAction.isPresent()) {
                if (moveAction.get()) {
                    continue;
                }
            } else {
                return;
            }

            moveAction = Move[stepFour.ordinal()].apply(this, currentPoint);
            if (moveAction.isPresent()) {
                if (moveAction.get()) {
                    continue;
                }
            } else {
                return;
            }
        }
    }
}
